package com.example.wac.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.example.wac.enums.ErrorCode;
import com.example.wac.exception.AppException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

/**
 * @author wuancheng
 * @description Excel工具类
 * @date 2022-01-13 14:00:00
 */

@Slf4j
public class EasyExcelUtils {
    /**
     * Excel文件读取
     *
     * @param file     导入的文件
     * @param clazz    导入Excel文件的对应映射DTO
     * @param listener 导入Excel的解析监听器
     */
    public static void read(MultipartFile file, Class<?> clazz, AnalysisEventListener<?> listener) {
        if (!isExcelFile(file)) {
            throw ErrorCode.FILE_TYPE_ERORR.getAppException();
        }
        try {
            EasyExcel.read(file.getInputStream(), clazz, listener).sheet().doRead();
        } catch (AppException e) {
            log.error("Excel文件导入，业务异常", e);
            throw e;
        } catch (ExcelAnalysisException e) {
            log.error("Excel文件导入，解析异常", e);
            /*
             * 解析Excel单元格过程中，业务异常被EasyExcel嵌套，需要通过e.getCause()取出。
             * 解析完成后的后续操作，抛出的业务异常可直接取到。
             * 详见：https://github.com/alibaba/easyexcel/issues/1026
             */
            if (e.getCause() instanceof AppException) {
                throw (AppException) e.getCause();
            }
            // 非业务异常
            throw e;
        } catch (Exception e) {
            log.error("Excel文件导入，其他异常", e);
            throw ErrorCode.SYSTEM_ERROR.getAppException(e);
        }
    }




    /**
     * 数据导出至Excel文件
     *
     * @param response HTTP返回请求
     * @param filePath Excel导出模板文件的路径。以resources为根目录。
     * @param data     导出至Excel模板的数据
     * @param fileName 导出的文件名称
     */
    public static void write(HttpServletResponse response, String filePath, Object data, String fileName) {
        InputStream inputStream = null;
        try {
            // 从classesPath路径下读取filePath目录名字的文件进内存（当前为(ClassesPath下的templates+文件名)）
            inputStream = EasyExcelUtils.class.getClassLoader().getResourceAsStream(filePath);
            // 设置响应体类型、编码格式和请求头信息
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
            // 一次填充(response.getOutputStream()是从内存写出到返回，withTemplate(inputStream).sheet().doFill(data)是将读取到内存的模板进行填充)
            EasyExcel.write(response.getOutputStream()).withTemplate(inputStream).sheet().doFill(data);
        } catch (IOException e) {
            log.error("Excel文件导出异常", e);
            throw ErrorCode.EXPORT_EXCEL_ERROR.getAppException(e);
        } finally {
            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    log.error("文件输入流关闭失败", e);
                }
            }
        }
    }

    /**
     * 判断上传的文件是否为Excel
     *
     * @param file
     * @return
     */
    public static boolean isExcelFile(MultipartFile file) {
        if (null == file || StringUtils.isBlank(file.getOriginalFilename())) {
            return false;
        }
        String originalFilename = file.getOriginalFilename();
        if (originalFilename.matches("^.+\\.(?i)(xlsx)$") || originalFilename.matches("^.+\\.(?i)(xls)$")) {
            return true;
        }
        return false;
    }
}

